package middleware

import (
	"app/api/v1/response"
	"app/internal/pkg/config"
	"app/internal/pkg/ecode"
	"errors"
	"time"

	"github.com/golang-jwt/jwt/v5"

	"github.com/gin-gonic/gin"
)

type UserClaims struct {
	ID      uint   `json:"id"`
	Account uint   `json:"account"`
	Name    string `json:"name"`
	jwt.RegisteredClaims
}

type JwtStruct struct {
	Secret []byte
}

var JWT = &JwtStruct{[]byte(config.JwtSecret)}

func (j *JwtStruct) GenerateToken(id, account uint, name string) (string, error) {
	claims := UserClaims{
		ID:      id,
		Account: account,
		Name:    name,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(config.JwtExpire)),
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString(j.Secret)
}

func (j *JwtStruct) ParserToken(tokenString string) (*UserClaims, error) {
	token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, func(*jwt.Token) (any, error) {
		return j.Secret, nil
	})
	if err != nil {
		if errors.Is(err, jwt.ErrTokenExpired) || errors.Is(err, jwt.ErrTokenNotValidYet) {
			return nil, ecode.ERROR_TOKEN_EXPIRED
		}
		return nil, err
	}
	if claims, ok := token.Claims.(*UserClaims); token.Valid && ok {
		return claims, nil
	}
	return nil, ecode.ERROR_TOKEN_EXPIRED
}

func (j *JwtStruct) RefreshToken(tokenString string) (string, error) {
	// TODO 刷新token
	return "", ecode.ERROR
}

func JwtAuth() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		// tokenHeader := ctx.Request.Header.Get("Authorization")
		tokenHeader, err := ctx.Cookie("token")
		if err != nil {
			response.Fail(ctx, err)
			ctx.Abort()
			return
		}
		claims, err := JWT.ParserToken(tokenHeader)
		if err != nil {
			response.Fail(ctx, err)
			ctx.Abort()
		}
		ctx.Set("claims", claims)
		ctx.Next()
	}
}
